前言
<form>
标签的属性 enctype
设置以何种编码方式提交表单数据。可选的值有三个:
application/x-www-form-urlencoded
multipart/form-data
text/plain
第一种:这是默认的编码方式。它只处理表单域里的 value
属性值,采用这种编码方式的表单会将表单域的值处理成URL方式。
第二种:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定的文件内容封装到请求参数里。
第三种:这种方式当表单的 action
属性值为 mailto:URL
的形式时比较方便,这种方式主要适用于直接通过表单发送邮件。
前端
<input type="file" name="pic">
标签用来提交文件。
要注意的是,这个标签的 value
值并不是所选择的文件内容,而是这个文件的完整路径名。
正如前面所说的,表单在提交表单时,如果采用默认编码方式,文件的内容是不会被提交的。 所以表单提交文件内容时要采用 multipart/form-data
编码方式,这需要在服务器端从提交的二进制流中读取文件内容。
后端
中间件的使用方式一般分为两种:
- 使用
app.use
的形式 - 在路由中作为参数的形式使用
我们使用 express
的中间件 multer
来接收上传的文件,multer
中间件是在路由中作为参数使用的。
-
multer
只会解析form
设置为enctype="multipart/form-data"
表单. -
multer
可以定制存储引擎 -
multer
会将上传的信息以及内容挂载到request
对象上
具体的使用步骤:
第一 导入 multer
中间件
const multer = require('multer');
第二 调用 multer
const upload = multer({dest: 'uploads/'}); //不采用这种方式
multer(options)
接受一个options
对象,其中最基本的是dest
属性,这将告诉multer
将上传文件保存在哪。如果你省略options
对象,这些文件将保存在内存中,永远不会写入磁盘。
dest
的意思是选择一个路径去存储文件,但是这样写有一个小小的问题,存入进来的文件是没有后缀名的。所以我们用下面的配置项
我们一般会使用一个配置项:
const storage = multer.diskStorage({
// 用来配置文件上传的位置
destination: (req, file, cb) => {
// 调用 cb 即可实现上传位置的配置
cb(null, './public/uploads')
},
// 用来配置上传文件的名称(包含后缀)
filename: (req, file, cb) => {
//filename 用于确定文件夹中的文件名的确定。 如果没有设置 filename,每个文件将设置为一个随机文件名,并且是没有扩展名的。
// 获取文件的后缀
let ext = path.extname(file.originalname)
// 拼凑文件名
cb(null, file.fieldname + '-' + Date.now() + ext)
}
})
const upload = multer({storage: storage})
router.post('/uploader', upload.single('pic'), (req, res) => {
// upload.single('pic') 意思是告诉 multer 只接收 name 是 pic 的单个文件
// 将上传成功的文件信息响应给浏览器
res.json(req.file)
})
重要:这里一定要注意一个路径问题,如果admin
路由是被引入到app.js
中使用的,在destination
中设置路径时,设置的是相对于app.js
的。
Tips
获取文件扩展名的方式(都是原生)
path.parse()
path.extname()
path.extname('index.html')
// 返回: '.html'
path.extname('index.coffee.md')
// 返回: '.md'
path.parse('/home/user/dir/file.txt')
// 返回:
// {
// root: '/',
// dir: '/home/user/dir',
// base: 'file.txt',
// ext: '.txt',
// name: 'file'
// }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。